﻿#region License

// PentaBiz - Sustainable Software Development Framework Copyright (C) 2013 Zoltán Csizmazia
// 
// This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

#endregion

using System;
using System.ComponentModel;
using System.Linq.Expressions;

namespace PentaBiz.Linq.Conditions
{
    /// <summary>
    ///     Condition for the specified entity's property
    /// </summary>
    /// <typeparam name="TEntity">The type of the entity.</typeparam>
    /// <typeparam name="TProperty">The type of the property.</typeparam>
    public abstract class Condition<TEntity, TProperty> : INotifyPropertyChanged, ICondition<TEntity>
    {
        protected readonly string PropertyName;

        /// <summary>
        ///     Initializes a new instance of the <see cref="Condition{TEntity, TProperty}" /> class.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        protected Condition(string propertyName)
        {
            PropertyName = propertyName;
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="Condition{TEntity, TProperty}" /> class.
        /// </summary>
        /// <param name="propertyExpression">The property expression.</param>
        protected Condition(Expression<Func<TEntity, TProperty>> propertyExpression)
        {
            PropertyName = propertyExpression.GetFullPropertyName();
        }

        #region ICondition<TEntity> Members

        /// <summary>
        ///     Builds the condition.
        /// </summary>
        /// <returns></returns>
        public abstract Expression<Func<TEntity, bool>> BuildCondition();

        #endregion

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        ///     Gets the property parameter expression.
        /// </summary>
        /// <param name="condition">The condition.</param>
        /// <returns>
        ///     <see cref="MemberExpression" /> for the property
        /// </returns>
        protected MemberExpression GetPropertyParameterExpression(ParameterExpression condition)
        {
            // Construct the nested properties
            string[] nestedProps = PropertyName.Split('.');
            Expression parameterExpression = condition;
            for (int i = 0; i < nestedProps.Length; i++)
                parameterExpression = Expression.PropertyOrField(parameterExpression, nestedProps[i]);
            return (MemberExpression) parameterExpression;
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}